import { ECSErr } from "../err/ECSErr";
import { Cls } from "../util/Defined";
import { RecyclePool } from "../util/Pool";
import { TypeUtil } from "../util/TypeUtil";
import { ECSCmp } from "./ECSCmp";
import { ECSEntity } from "./ECSEntity";
import { ECSMgr } from "./ECSMgr";

/**
 * [ECS]组件管理
 */
export class ECSCmpMgr extends ECSMgr {
	/** 维护组件类型的唯一标识 通过该标识去设置实体的组件bits 方便组件过滤器去比对筛选 */
	protected _idxMap = new Map<Cls<ECSCmp>, number>();
	/** 唯一标识映射组件类型 */
	protected _typeMap = new Map<number, Cls<ECSCmp>>();
	/** 组件对象池映射 */
	protected _poolMap = new Map<Cls<ECSCmp>, RecyclePool<ECSCmp>>();
	/** 等待移除的组件 */
	protected _waitRemoveCmps = new Set<ECSCmp>();

	/**
	 * 获取组件类型的idx标识
	 * @param cmp
	 */
	getTypeIdx(cmp: Cls<ECSCmp>) {
		if (this._idxMap.has(cmp)) {
			return this._idxMap.get(cmp);
		}
		const idx = this._idxMap.size;
		this._idxMap.set(cmp, idx);
		return idx;
	}

	/**
	 * 通过idx标识获取组件类型
	 * @param idx 
	 */
	getType(idx: number) {
		return this._typeMap.get(idx);
	}

	/**
	 * 创建实体组件
	 * @param entity 实体
	 * @param cmpType 组件类型
	 */
	create<T extends ECSCmp>(entity: ECSEntity, cmpType: Cls<T>) {
		if (entity.cmpMap.has(cmpType)) {
			this.scene.logger.error(new ECSErr("实体重复添加同个组件"));
			return;
		}

		let pool = this._poolMap.get(cmpType);
		if (!pool) {
			pool = new RecyclePool(cmpType);
			this._poolMap.set(cmpType, pool);
		}
		const cmp = pool.alloc();
		cmp.scene = this.scene;
		cmp.entity = entity;
		cmp.entityId = entity.id;
		entity.cmpMap.set(cmpType, cmp);
		//将组件类型对应bit设为true
		entity.cmpBits.setBit(this.getTypeIdx(cmpType), true);
		cmp.onAdd?.();
		if (entity.applyed) {
			//通知过滤器组件添加
			this.scene.filterMgr.onEntityCmpUpdate(entity, cmpType);
			cmp.onApply?.();
		}

		return cmp as T;
	}

	/**
	 * 移除组件
	 * @param cmp
	 */
	remove(cmp: ECSCmp) {
		if (!cmp) return;
		if (this.scene.inFrame) {
			this._waitRemoveCmps.add(cmp);
		} else {
			this.checkRemoveCmp(cmp);
			this.removeCmp(cmp);
		}
	}

	/**
	 * 更新组件
	 */
	update() {
		if (this._waitRemoveCmps.size > 0) {
			//检测组件移除
			this._waitRemoveCmps.forEach(this.checkRemoveCmp, this);
		}
	}

	/**
	 * 更新组件移除
	 */
	updateRemove() {
		if (this._waitRemoveCmps.size > 0) {
			//组件真正移除
			this._waitRemoveCmps.forEach(this.removeCmp, this);
			this._waitRemoveCmps.clear();
		}
	}

	private checkRemoveCmp(cmp: ECSCmp) {
		const cmpType = TypeUtil.getCls(cmp);
		const entity = cmp.entity;
		//将组件类型对应bit设为false
		entity.cmpBits.setBit(this.getTypeIdx(cmpType), false);
		//通知过滤器
		this.scene.filterMgr.onEntityCmpUpdate(entity, cmpType);
	}

	private removeCmp(cmp: ECSCmp) {
		const cmpType = TypeUtil.getCls(cmp);
		const entity = cmp.entity;
		entity.cmpMap.delete(cmpType);
		entity.offCaller(cmp);
		cmp.onRemove?.();
		cmp.free();
	}

	protected onDestroy(): void {
		this._idxMap.clear();
		this._typeMap.clear();
		this._poolMap.clear();
	}
}
